package basedi

import (
	"gitee.com/ichub/goconfig/common/base/baseiface"
	"github.com/sirupsen/logrus"
	"reflect"
	"sync"
)

func RegisterLoadBean(name string, loadbean baseiface.LoadBean) {
	container.RegisterLoadBean(name, loadbean)
}

func RegisterBean(name string, bean baseiface.ISingleton) {
	container.RegisterBean(name, bean)
}

func FindBean(name string) baseiface.ISingleton {
	var beanInfo, _ = container.FindBean(name)
	if beanInfo == nil {
		return nil
	}
	if beanInfo.bean.Single() {
		return beanInfo.Bean()
	}
	return beanInfo.CreateBean()
}
func FindBeanOk(name string) (baseiface.ISingleton, bool) {
	var beanInfo, ok = container.FindBean(name)
	if beanInfo == nil {
		return nil, ok
	}
	if beanInfo.bean.Single() {
		return beanInfo.Bean(), ok
	}
	return beanInfo.CreateBean(), ok
}

func FindBeanInst[T any]() T {
	var t T
	var instType = reflect.TypeOf(t)
	var intance, ok = FindBeanOk(instType.String()[1:])
	if !ok {
		intance, ok = FindBeanOk(instType.String())
	}
	return intance.(T)
}
func FindBeanInstOk[T any]() (T, bool) {
	var t T
	var instType = reflect.TypeOf(t)
	var intance, ok = FindBeanOk(instType.String()[1:])
	if !ok {
		intance, ok = FindBeanOk(instType.String())
	}
	return intance.(T), ok
}

func FindBeanProxy(name string) baseiface.IbaseProxy {
	//return FindBean(name).(baseiface.IbaseProxy)
	proxy, ok := FindBean(name).(baseiface.IbaseProxy)
	if !ok {
		logrus.Error("Type assertion to ibaseProxy failed for ", name)
		return nil
	}
	return proxy
}

type beanContainer struct {
	container map[string]*BeanInfo

	lock sync.RWMutex
}

var container = newBeanContainer()

func newBeanContainer() *beanContainer {
	return &beanContainer{
		container: make(map[string]*BeanInfo),
		lock:      sync.RWMutex{},
	}
}

func (this *beanContainer) FindBean(name string) (*BeanInfo, bool) {
	this.lock.RLock()
	defer this.lock.RUnlock()

	var beanInfo, ok = this.container[name]
	if !ok {
		logrus.Error(name, " bean found?", ok)
		return nil, ok
	}
	if beanInfo.bean == nil {
		beanInfo.SetBean(beanInfo.CreateBean())
		this.autoInjectConfigItem(beanInfo)
	}

	return beanInfo, ok
}

func (this *beanContainer) autoInjectConfigItem(beanInfo *BeanInfo) {
	if ibcfg, ok := beanInfo.bean.(baseiface.IbaseConfig); ok {
		ibcfg.InjectConfigItem(ibcfg)
	}
}
func (this *beanContainer) RegisterLoadBean(name string, loadbean baseiface.LoadBean) {
	this.lock.Lock()
	defer this.lock.Unlock()

	var beanInfo = NewBeanInfo()
	beanInfo.SetBeanName(name)
	beanInfo.SetLoadBean(loadbean)
	this.container[name] = beanInfo
}

func (this *beanContainer) RegisterBean(name string, bean baseiface.ISingleton) {
	this.lock.Lock()
	defer this.lock.Unlock()

	var beanInfo = NewBeanInfo()
	beanInfo.SetBeanName(name)
	beanInfo.SetBean(bean)
	this.container[name] = beanInfo
}

func (this *beanContainer) CreateBean(beanInfo *BeanInfo) baseiface.ISingleton {

	return beanInfo.CreateBean()
}
